﻿using GraphDrawing2.V2.Graph.Model;

namespace GraphDrawing2.V2.Concrete.Model
{
    public interface IHitTestResult
    {
        HitTestType Type { get; }
        IVisualObject Object { get; }
        T ProcessBy<T>(IHitTestResultVisitor<T> operation);
    }

    public interface IHitTestResultVisitor<out T>
    {
        T OnNone(NoneHitTest none);
        T OnElement(ElementHitTest element);
        T OnConnector(ConnectorHitTest connector);
    }

    public class NoneHitTest : IHitTestResult
    {
        public static readonly NoneHitTest INSTANCE = new NoneHitTest();

        NoneHitTest()
        {
        }

        public HitTestType Type
        {
            get { return HitTestType.NONE; }
        }

        public IVisualObject Object
        {
            get { return null; }
        }

        public T ProcessBy<T>(IHitTestResultVisitor<T> operation)
        {
            return operation.OnNone(this);
        }
    }


    public class ElementHitTest : IHitTestResult
    {
        public HitTestType Type
        {
            get { return HitTestType.ELEMENT; }
        }

        public IVisualElement Element { get; private set; }

        public ElementHitTest(IVisualElement element)
        {
            Element = element;
        }

        IVisualObject IHitTestResult.Object
        {
            get { return Element; }
        }

        public T ProcessBy<T>(IHitTestResultVisitor<T> operation)
        {
            return operation.OnElement(this);
        }
    }


    public class ConnectorHitTest : IHitTestResult
    {
        public HitTestType Type
        {
            get { return HitTestType.CONNECTOR; }
        }

        public ConnectorOrigin Origin { get; private set; }

        public ConnectorHitTest(ConnectorOrigin origin)
        {
            Origin = origin;
        }

        IVisualObject IHitTestResult.Object
        {
            get { return Origin.Connector; }
        }

        public T ProcessBy<T>(IHitTestResultVisitor<T> operation)
        {
            return operation.OnConnector(this);
        }
    }


    public enum HitTestType
    {
        NONE,
        ELEMENT,
        CONNECTOR,
        CONNECTION
    }
}